package com.xhj.ipersistent.executor;

import com.xhj.ipersistent.config.Configuration;
import com.xhj.ipersistent.mapping.BoundSql;
import com.xhj.ipersistent.mapping.MappedStatement;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

/**
 * BaseExecutor
 *
 * @author XJks
 * @description 执行器接口的基础实现类
 * <p>
 * TODO:
 *  问题:对于CRUD操作，该类为什么只有Update和Query方法，而没有Insert和Delete方法?
 *  答案:
 *      1.在SQL语句层面
 *          1.1 Insert，Delete，Update的返回值都是int类型，表示影响的行数
 *          1.2 Select的返回值是List<E>类型，表示查询结果集
 *          1.3 根据上述两点，可以将Insert，Delete，Update三种操作归为一类，Select归为另一类
 *      2.在JDBC层面
 *          2.1 根据JDBC的API，执行增删改操作使用的是{@link PreparedStatement#executeUpdate()}方法，执行查询操作使用的是{@link PreparedStatement#executeQuery()}方法
 *          2.2 {@link PreparedStatement#executeUpdate()}方法的返回值是int类型，{@link PreparedStatement#executeQuery()}方法的返回值是ResultSet类型
 *          2.3 根据上述两点，可以将Insert，Delete，Update三种操作归为一类，Select归为另一类
 *      3.总结
 *          3.1 无论是在SQL语句层面，还是在JDBC层面，Insert，Delete，Update三种操作都是一类，Select是另一类
 *          3.2 因此，在设计执行器接口时，将Insert，Delete，Update三种操作归为一类，使用update()方法表示，Select操作单独使用query()方法表示
 */
public abstract class BaseExecutor implements Executor {
    /**
     * 全局配置对象
     */
    protected Configuration configuration;

    /**
     * JDBC原生对象Connection
     */
    protected Connection connection = null;

    /**
     * JDBC原生对象PreparedStatement
     */
    protected PreparedStatement preparedStatement = null;

    /**
     * JDBC原生对象ResultSet
     */
    protected ResultSet resultSet = null;

    public BaseExecutor(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public int update(MappedStatement mappedStatement, Object parameter) throws SQLException {
        return doUpdate(mappedStatement, parameter);
    }

    @Override
    public <E> List<E> query(MappedStatement mappedStatement, Object parameter) throws SQLException {
        BoundSql boundSql = mappedStatement.getBoundSql();
        return query(mappedStatement, parameter, boundSql);
    }

    @Override
    public <E> List<E> query(MappedStatement mappedStatement, Object parameter, BoundSql boundSql) throws SQLException {
        // TODO:可以在方法中进行扩展，加入相关缓存逻辑
        List<E> list = queryFromDatabase(mappedStatement, parameter, boundSql);
        return list;
    }

    /**
     * TODO: 实际向数据库发起查询的方法
     */
    private <E> List<E> queryFromDatabase(MappedStatement mappedStatement, Object parameter, BoundSql boundSql) throws SQLException {
        List<E> list = doQuery(mappedStatement, parameter, boundSql);
        return list;
    }

    /**
     * TODO: 交给子类去实现具体的更新操作，该方法需由子类使用原生JDBC完成
     */
    protected abstract int doUpdate(MappedStatement mappedStatement, Object parameter) throws SQLException;

    /**
     * TODO: 交给子类去实现具体的查询操作，该方法需由子类使用原生JDBC完成
     */
    protected abstract <E> List<E> doQuery(MappedStatement mappedStatement, Object parameter, BoundSql boundSql) throws SQLException;

    @Override
    public void close() {
        // 释放资源
        try {
            if (resultSet != null) {
                resultSet.close();
            }
            if (preparedStatement != null) {
                preparedStatement.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取数据库连接
     */
    @Override
    public Connection getConnection() {
        try {
            if (connection == null || connection.isClosed()) {
                // 通过驱动管理类获取数据库链接
                connection = configuration.getDataSource().getConnection();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
}
